--------------Word Attack!-------------
A 4am crack                  2015-11-01
---------------------------------------

Name: Word Attack!
Version:
  title screen says (c) 1983, 1985
  disk label says (c) 1985, v06.01.87
  newest file in catalog is 17-DEC-87
Genre: educational
Year: 1987
Authors: Richard Eckert and Janice
  Davidson, Ph.D.
Publisher: Davidson & Associates, Inc.
Media: 3.5-inch floppy (800K)
OS: ProDOS 1.4
Previous cracks: none

                   ~

               Chapter 0
 In Which Various Automated Tools Fail
          In Interesting Ways


Copy ][+ 9.1 ("COPY" > "DISK")
  read error on block $0308; copy loads
  ProDOS, displays a prompt, prints
  "PLEASE PRESS SPACE BAR", and crashes

CFFA 3000 import
  read error on block 776 (= $0308);
  booting the disk image in an emulator
  exhibits the same behavior as the
  backup I made with Copy ][+ disk copy

The original disk boots without
complaint, so either this bad block is
part of the protection check, or it's
unrelated and I got incredibly lucky.

Next steps:

  1. Trace the startup program
  2. Find and disable the protection
     check
  3. Declare victory(*)

(*) Take a nap

                   ~

               Chapter 1
          Success Is Failure,
          Failure Is Success,
            Black Is White,
             Night Is Day,
           Teaching Is Dead


[S7,D1=my ProDOS hard drive]
[S5,D1=non-working copy]

]PR#7
...
]CAT,S5,D1

/WORD

 NAME           TYPE  BLOCKS  MODIFIED

*DATA            DIR       3  17-DEC-87
*PICTURES        DIR       1  25-OCT-87
*PRODOS          SYS      32  17-APR-87
*BASIC.SYSTEM    SYS      21  15-NOV-83
*STARTUP         BAS      39   6-OCT-87
*WORD.C          BAS      28  25-OCT-87
*DEMO            BAS      14  25-OCT-87
*EDITOR          BAS      20  17-NOV-87
 DESKTOP         $00       3  16-SEP-56

BLOCKS FREE: 1063     BLOCKS USED:  537


I saw a BASIC prompt during boot (even
on my unsuccessful copy), so let's
start with STARTUP.BAS.

]PREFIX /WORD
]LOAD STARTUP
]LIST

 10  CALL 9361

Ah! A fake BASIC program that really
calls the embedded assembly language
program within it.

9361 = $2491. Let's see what's there.

]CALL -151

*2491L

2491-   4C 94 24    JMP   $2494

*2494L

2494-   20 00 24    JSR   $2400

*2400L

; save registers, flags, and several
; zero page locations
2400-   08          PHP
2401-   48          PHA
2402-   98          TYA
2403-   48          PHA
2404-   8A          TXA
2405-   48          PHA
2406-   A5 F8       LDA   $F8
2408-   48          PHA
2409-   A5 F9       LDA   $F9
240B-   48          PHA
240C-   A5 FA       LDA   $FA
240E-   48          PHA

; get unit number (slot+drive, but in a
; weird format that ProDOS likes)
240F-   AD 30 BF    LDA   $BF30
2412-   4A          LSR
2413-   4A          LSR
2414-   4A          LSR
2415-   4A          LSR
2416-   29 07       AND   #$07
2418-   09 C0       ORA   #$C0

; so this is the boot slot, munged into
; $Cx form (so $C6 for slot 6)
241A-   85 F9       STA   $F9
241C-   A9 00       LDA   #$00
241E-   85 F8       STA   $F8

; now look at some signature bytes in
; the peripheral ROM for the boot slot
; to determine what kind of floppy
; disk we booted from (5.25" or 3.5")
2420-   A0 01       LDY   #$01
2422-   B1 F8       LDA   ($F8),Y
2424-   C9 20       CMP   #$20
2426-   D0 22       BNE   $244A
2428-   A0 03       LDY   #$03
242A-   B1 F8       LDA   ($F8),Y
242C-   D0 1C       BNE   $244A
242E-   A0 05       LDY   #$05
2430-   B1 F8       LDA   ($F8),Y
2432-   C9 03       CMP   #$03
2434-   D0 14       BNE   $244A
2436-   A0 FF       LDY   #$FF
2438-   B1 F8       LDA   ($F8),Y
243A-   D0 0E       BNE   $244A

; if 5.25-inch, use block $110 (which
; is somewhere on track $22)
243C-   A9 10       LDA   #$10
243E-   8D 04 22    STA   $2204
2441-   A9 01       LDA   #$01
2443-   8D 05 22    STA   $2205
2446-   D0 0C       BNE   $2454
2448-   F0 0A       BEQ   $2454

; if 3.5-inch, use block $308 (this is
; the block I couldn't read when I
; tried to copy the disk)
244A-   A9 08       LDA   #$08
244C-   8D 04 22    STA   $2204
244F-   A9 03       LDA   #$03
2451-   8D 05 22    STA   $2205

; fill out the rest of an MLI parameter
; table
2454-   AD 30 BF    LDA   $BF30
2457-   8D 01 22    STA   $2201
245A-   A9 03       LDA   #$03
245C-   8D 00 22    STA   $2200
245F-   A9 00       LDA   #$00
2461-   8D 02 22    STA   $2202
2464-   A9 20       LDA   #$20
2466-   8D 03 22    STA   $2203

; now call the ProDOS MLI to perform a
; raw block read on the specified block
2469-   20 00 BF    JSR   $BF00
246C-  [80 00 22]

; if there was NOT a disk read error,
; then branch
246F-   90 0C       BCC   $247D
2471-   85 FA       STA   $FA

; if there was any error other than an
; I/O error ($27), then branch
2473-   C9 27       CMP   #$27
2475-   D0 06       BNE   $247D

; success path falls through to here --
; set a flag in zero page
2477-   A9 FF       LDA   #$FF
2479-   85 FF       STA   $FF
247B-   D0 04       BNE   $2481

; failure path is here (via $246F or
; $2475) -- set the magic zero page
; flag to $00 instead of $FF
247D-   A9 00       LDA   #$00
247F-   85 FF       STA   $FF

; restore everything on the way out
; (except the magic flag at zp$FF)
2481-   68          PLA
2482-   85 FA       STA   $FA
2484-   68          PLA
2485-   85 F9       STA   $F9
2487-   68          PLA
2488-   85 F8       STA   $F8
248A-   68          PLA
248B-   AA          TAX
248C-   68          PLA
248D-   A8          TAY
248E-   68          PLA
248F-   28          PLP
2490-   60          RTS

Continuing from $2497...

; munge reset vector
2497-   A0 FF       LDY   #$FF
2499-   8C F4 03    STY   $03F4

; set RUN flag
249C-   A0 80       LDY   #$80
249E-   8C D6 00    STY   $00D6

; check magic zero page flag that was
; set by the bad block check at $2400
24A1-   A0 FF       LDY   #$FF
24A3-   C4 FF       CPY   $FF
24A5-   F0 03       BEQ   $24AA

; very bad
24A7-   6C F2 03    JMP   ($03F2)

; very good
24AA-   A0 40       LDY   #$40
24AC-   8C 68 00    STY   $0068
24AF-   4C 66 D5    JMP   $D566

This is definitely a form of copy
protection. (Fun fact: it appears to be
written so it can be re-used for 5.25-
and 3.5-inch floppies.) It relies on
one specific block or sector being
unreadable, and fails if it's actually
readable. Since my copy didn't
reproduce the badness of block $308,
the MLI read routine unexpectedly
succeeds, and the program knows it's
been copied.

To bypass the protection, I can change
the failure path at $247D so it sets
the magic zero page flag to $FF instead
of $00.

Block Warden
  ["C"hange device -> S5,D1]
  ["F"ollow file]
    ["STARTUP"]

Block $01C4, offset $7D change 00 to FF

]PR#5
...works...

Quod erat liberandum.

---------------------------------------
A 4am crack                     No. 480
------------------EOF------------------
